#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QWidget>
#include <QDebug>
#include <QMessageBox>
#include <QDir>
#include <QScreen>
#include <QDateTime>
#include <QFileDialog>
#include <QGuiApplication>

#include "recvcanprotmanager.h"
#include "sendcanprotmanager.h"
#include "PCANBasic.h"



MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , pcanReceiver(nullptr)
    , canLogger(new CanAscLogger(this))
    , sendTimer(new QTimer(this))  // 初始化定时器
    , HLOutTimer(new QTimer(this))  // 初始化定时器
    , concurrentSemaphore(10) // 限制最大5个并发进程
    , sendTimerSerial(new QTimer(this))  // 初始化定时器
{
    ui->setupUi(this);
    setWindowTitle("Brainbox-J300P 上位机软件");

    setLabelLightStyle();

    lastTimestampMap["MCU_44"] = -1;
    lastTimestampMap["MCU_45"] = -1;
    lastTimestampMap["MCU_46"] = -1;

    // 其他初始化代码...
    canLogger = new CanAscLogger(this);

    // 初始化CAN报文管理器
    m_canProtManager = new SendCANProtManager();

    // 配置定时器：100ms间隔
    sendTimer->setInterval(100);  // 100ms
    // 连接定时器信号到发送槽函数
    connect(sendTimer, &QTimer::timeout, this, &MainWindow::onSendCanMessages);

    HLOutTimer->setInterval(1000);
    connect(HLOutTimer, &QTimer::timeout, this, [this](){
        this->HLPower = !this->HLPower;
    });

    sendTimerSerial->setInterval(1000);
    m_isSending = false;
    // 连接计时器超时信号到发送函数
    connect(sendTimerSerial, &QTimer::timeout, this, &MainWindow::onSerialSendTimeout);
    initSerialManagers();

    inintemperatureCurve();

    return;
}

MainWindow::~MainWindow()
{
    delete ui;

    // 释放所有iperf3进程（使用QMap管理时）
    // 遍历所有进程并安全终止
    QMapIterator<QString, QProcess*> iter(iperf3ProcessMap);
    while (iter.hasNext()) {
        iter.next();
        const QString &id = iter.key();
        QProcess *process = iter.value();

        if (process) {
            // 终止进程（带超时处理）
            if (process->state() == QProcess::Running) {
                process->terminate();
                if (!process->waitForFinished(1000)) {
                    process->kill();
                }
            }
            delete process;
        }
        processRunningMap.remove(id); // 清理状态
    }
    iperf3ProcessMap.clear();

    if (pcanReceiver) {
        pcanReceiver->disconnectDevice();
        delete pcanReceiver;
    }

    delete sendTimer;

    // 清理所有串口管理器
    for (auto port : m_serialPorts) {
        delete port;
    }

    if (m_udpSocket) {
        delete m_udpSocket;
    }
}

void MainWindow::on_saveFilePushButton_clicked()
{
    QString defaultPath = QString(PROJECT_DIR) + "/log/";
    QDir dir(defaultPath);
    if (!dir.exists()) {
        dir.mkpath("."); // 创建目录
    }

    // 弹出文件夹选择对话框
    QString selectedPath = QFileDialog::getExistingDirectory(
        this,
        "选择保存路径",
        defaultPath // QDir::currentPath() // 默认从当前程序目录开始
    );

    if (!selectedPath.isEmpty()) {
        ui->folderPath->setText(selectedPath); // 显示选中的路径
    }

    QWidget *widget0 = ui->widget_0->widget(0);
    QLineEdit* fileName = widget0->findChild<QLineEdit*>("dataFileName");
    QCheckBox* isChecked = widget0->findChild<QCheckBox*>("checkSavefolder");
    if( isChecked->isChecked() ){
        PCANlog = true;
        ascPath = selectedPath + "/" + fileName->text();
        qInfo() << "PCAN通信日志记录文件名:" << ascPath;
    }
    else
        qInfo() << "复选框没有勾选，不保存日志文件...";

    return;
}

void MainWindow::setLabelLightStyle()
{
    // 绿色背景 #4CAF50 莹绿色 #7FFF00 中灰色 #A0A0A0 黄色 #FFFF00 红色 #FF0000  中深灰 #424242
    ui->widget_can->setStyleSheet(
            // 匹配 QTabWidget 下 QGroupBox 中所有对象名含 "circleColors_" 的 Label
            "QTabWidget QGroupBox QLabel[objectName*=circleColors_] {"
            "   border-radius: 12px;"                // 圆形（半径=宽高的一半）
            "   background-color: #424242;"          //中深灰 #424242
            "   border: 2px solid #2E7D32;"          // 深绿色边框
            "   min-width: 20px; min-height: 20px;"  // 固定尺寸（确保正方形）
            "   max-width: 20px; max-height: 20px;"
            "}"

        );

    ui->widget_0->setStyleSheet(
        "QTabWidget QLabel[objectName*=Title] {"
        "color: blue; font-size: 20px;"
        "}"
        );

}

//截图功能
void MainWindow::on_savePixMap_clicked()
{
    // 获取屏幕对象
    QScreen *screen = QGuiApplication::primaryScreen();
    if (!screen) {
        QMessageBox::warning(this, "错误", "无法获取屏幕对象");
        return;
    }

    // 捕获当前窗口：
    QPixmap screenshot = screen->grabWindow(this->winId());

    // 生成带时间戳的文件名（避免重复）
    QString timeStamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
    QString fileName = QString("HostComputer_%1.png").arg(timeStamp);

    QString sPath = QFileDialog::getSaveFileName(this, "保存截图",
                         fileName, "PNG图片 (*.png);;所有文件 (*)");
    if (!sPath.isEmpty()) {
        if (!screenshot.save(sPath)) {
            QMessageBox::critical(this, "错误", "保存截图失败！");
        }
    }

    return;
}

//展示更新应答的数据
void MainWindow::updateDataIperf3(const int &index,const QString &dTabWidget,const QString &lostPack,const QString &totalPack, const QString &lostRate,const QString &labellossC,const QString &passButton)
{
    //updateDataIperf3(const int &index,const QString &dTabWidget,const QString &lostPack,const QString &totalPack, const QString &lostRate,const QString &lossCount,const QString &passButton)
    //updateDataIperf3(0, "P1_1_TabWidget", "P1_1_LostPackets", "P1_1_TotalPackets", "P1_1_LossRate"，"P1_1_LossCount"，"P1_1_Pass")
    QWidget *widget0 = ui->widget_0->widget(1);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_eth");
    QWidget *widget1 = secondTab->widget(index);
    QTableWidget *dataTableWidget = widget1->findChild<QTableWidget*>(dTabWidget);

    if( dataTableWidget && dataTableWidget->rowCount() == 0 )
    {
        // 1. 强制显示表格（防止被意外隐藏）
        dataTableWidget->setVisible(true);
        // 2. 显式设置列数（与表头数量必须一致！这是关键！）
        dataTableWidget->setColumnCount(4); // 表头有4项，列数必须设为4
        dataTableWidget->setFixedSize(491, 201);
        // 设置第每列宽度
        dataTableWidget->setColumnWidth(0, 160);
        dataTableWidget->setColumnWidth(1, 95);
        dataTableWidget->setColumnWidth(2, 95);
        dataTableWidget->setColumnWidth(3, 138);
        dataTableWidget->setShowGrid(false);  // 不显示单元格之间的网格线
        //数据只读
        dataTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
        // 设置表头（对应原第二、三、四列）
        QStringList headers;
        headers << "时间" << "Interval(s)" << "Transfer" << "Bandwidth"; // 跳过原第一列的标题
        dataTableWidget->setHorizontalHeaderLabels(headers);
        // 关键：强制显示水平表头
        dataTableWidget->horizontalHeader()->setVisible(true);
        // 调整表头高度（避免高度为0导致不可见）
        dataTableWidget->horizontalHeader()->setMinimumHeight(30);
        // 关键：隐藏垂直表头
        dataTableWidget->verticalHeader()->setVisible(false);

    }

    int newRow = dataTableWidget->rowCount();
    dataTableWidget->insertRow(newRow);
    dataTableWidget->setItem(newRow, 0, new QTableWidgetItem(timeStamp));
    dataTableWidget->setItem(newRow, 1, new QTableWidgetItem(interval));
    dataTableWidget->setItem(newRow, 2, new QTableWidgetItem(transfer));
    dataTableWidget->setItem(newRow, 3, new QTableWidgetItem(bandwidth));

    //updateDataIperf3(const int &index,const QString &dTabWidget,const QString &lostPack,const QString &totalPack, const QString &lostRate,const QString &lossCount,const QString &passButton)
    //updateDataIperf3(0, "P1_1_TabWidget", "P1_1_LostPackets", "P1_1_TotalPackets", "P1_1_LossRate"，"P1_1_LossCount"，"P1_1_Pass")
    QLabel *labelLostPackets = widget1->findChild<QLabel*>(lostPack); // 丢包数
    if (labelLostPackets) labelLostPackets->setText(QString::number(lostPackets));
    QLabel *labelTotalPacket = widget1->findChild<QLabel*>(totalPack);   //发送总数
    if (labelTotalPacket) labelLostPackets->setText(QString::number(totalPackets));
    QLabel *labelLostRate = widget1->findChild<QLabel*>(lostRate);  // 丢包率(%)
    QString numericStr = lossRate;
    numericStr.remove('%');
    double numericValue = numericStr.toDouble(); // 转换为 double
    if (labelLostRate)  labelLostRate->setText(QString::number(numericValue, 'f', 2) + "%"); // 丢包率(%)
    QLabel *labelLostCount = widget1->findChild<QLabel*>(labellossC);  // 丢包次数
    if (labelLostCount)  labelLostCount->setText(QString::number(lossCount));

    // 更新状态按钮样式
    QPushButton *statusBtn = widget1->findChild<QPushButton*>(passButton);
    if (statusBtn) {
      //默认莹绿色 通过
      statusBtn->setStyleSheet("background-color: #00FF00; color: black;");
      if (numericValue > 0.0000001) {
          statusBtn->setStyleSheet("background-color: red; color: white;");
      }
    }

    dataTableWidget->scrollToBottom();
    dataTableWidget->viewport()->update();

    return;
}


//解析 Iperf3 进程数据
void MainWindow::parseIperf3Data(const QString &output, const QString &id, const int &index,const QString &dTabWidget,const QString &lostPack,const QString &totalPack, const QString &lostRate,const QString &labellossC,const QString &passButton)
{
    qInfo() << "MainWindow::parseIperf3Data:" << output;
    // iperf3 典型输出（客户端 TCP 模式）（实时输出）
    QRegularExpression realtimeRe(
        R"(\[\s*\d+\]\s*(\d+\.\d+-\d+\.\d+)\s+sec\s+([\d\.]+ \w+Bytes?)\s+([\d\.]+ \w+bits/sec)\s+(\d+)\s+[\d\.]+\s+\w+Bytes?)"
    );

    // 丢包数据解析（总结行）
    QRegularExpression lossRe(
        R"(\[\s*\d+\]\s*(\d+\.\d+-\d+\.\d+)\s+sec\s+([\d\.]+ \w+Bytes?)\s+([\d\.]+ \w+bits/sec)\s+(\d+)\s+.*sender)"
    );

    // 先解析实时带宽数据
    QRegularExpressionMatch match = realtimeRe.match(output);
    if (match.hasMatch()) {
        interval = match.captured(1);
        transfer = match.captured(2);
        bandwidth = match.captured(3);
        timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
        // 丢包字段默认初始化
        lostPackets = 0;
        totalPackets = 0;
        lossRate = "0.00%";
        lossCount = 0;
        QMetaObject::invokeMethod(this, "updateDataIperf3",
                                 Qt::QueuedConnection,
                                 Q_ARG(int, index),
                                 Q_ARG(QString, dTabWidget),
                                 Q_ARG(QString, lostPack),
                                 Q_ARG(QString, totalPack),
                                 Q_ARG(QString, lostRate),
                                 Q_ARG(QString, labellossC),
                                 Q_ARG(QString, passButton));
        //updateDataIperf3(index, dTabWidget, lostPack, totalPack, lostRate, labellossC, passButton);
        return;
    }

    // 再解析丢包数据（总结行）
    QRegularExpressionMatch lossMatch = lossRe.match(output);
    if (lossMatch.hasMatch()) {
        interval = lossMatch.captured(1);
        transfer = lossMatch.captured(2);
        bandwidth = lossMatch.captured(3);
        timeStamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
        // 提取丢包相关数据
        lostPackets = lossMatch.captured(4).toInt();      // 丢包数
        totalPackets = lossMatch.captured(5).toInt();     // 发送总数
        lossRate = lossMatch.captured(6) + "%";           // 丢包率
        lossCount = lostPackets;                       // 丢包次数（与丢包数一致）

        QMetaObject::invokeMethod(this, "updateDataIperf3",
                                 Qt::QueuedConnection,
                                 Q_ARG(int, index),
                                 Q_ARG(QString, dTabWidget),
                                 Q_ARG(QString, lostPack),
                                 Q_ARG(QString, totalPack),
                                 Q_ARG(QString, lostRate),
                                 Q_ARG(QString, labellossC),
                                 Q_ARG(QString, passButton));
        //updateDataIperf3(index, dTabWidget, lostPack, totalPack, lostRate, labellossC, passButton);
    }

}

// 错误处理
void MainWindow::onIperf3ErrorOccurred(const QString &id, const int &index, const QString &errorMsg)
{
    qWarning() << "[" << id << "] iperf3错误：" << errorMsg;

    // 找到对应ID的错误显示控件
    QWidget *widget0 = ui->widget_0->widget(1);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_eth");
    QWidget *widget1 = secondTab->widget(index); // 可根据实际情况调整index
    QTextEdit *textBad = widget1->findChild<QTextEdit*>(id + "_bad");

    if (textBad) {
        textBad->setText("错误：" + errorMsg);
    }
}

// 进程结束处理（清理资源）
void MainWindow::onProcessFinished(const QString &id, const int &index, int exitCode, QProcess::ExitStatus exitStatus)
{
    qInfo() << "[" << id << "] 进程结束，退出码：" << exitCode;

    QMutexLocker locker(&runningMapMutex);
    // 更新状态
    processRunningMap[id] = false;

    // 释放信号量
    concurrentSemaphore.release();

    // 更新按钮文本
    QWidget *widget0 = ui->widget_0->widget(1);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_eth");
    QWidget *widget1 = secondTab->widget(index);
//    QTextEdit *textBad = widget1->findChild<QTextEdit*>(id + "_bad");
//    if (exitCode != 0 && textBad) {
//        textBad->setText("进程异常退出，退出码：" + QString::number(exitCode)
//                        + "\n可能原因：服务器忙碌或连接失败");
//    }

    QPushButton *btStart = widget1->findChild<QPushButton*>(id + "_Start");
    if (btStart) {
        btStart->setText("启动");
    }
}

//Iperf3 进程输出
void MainWindow::onIperf3OutputReady(const QString &id, const int &index,const QString &dTabWidget,const QString &lostPack,const QString &totalPack, const QString &lostRate,const QString &labellossC,const QString &passButton)
{
    // 读取 iperf3 的标准输出 + 错误输出
    QProcess *iperf3Process = iperf3ProcessMap.value(id, nullptr);
    if (!iperf3Process) return;

//    QByteArray outputBytes = iperf3Process->readAllStandardOutput()
//                           + iperf3Process->readAllStandardError();
    QByteArray outputBytes = iperf3Process->readAll();

    QString output = QString::fromUtf8(outputBytes);

    qInfo() << "[" << id << "] onIperf3OutputReady: " << output;

    if (output.contains("error", Qt::CaseInsensitive)) {
       // 触发错误处理函数
       onIperf3ErrorOccurred(id, index, output);
       //自动停止异常进程
       iperf3Process->terminate();
    }

    // 逐行解析
    QStringList lines = output.split('\n', QString::SkipEmptyParts);
    foreach (const QString &line, lines) {
        QString trimmedLine = line.trimmed();
        if (!trimmedLine.isEmpty()) {
            parseIperf3Data(trimmedLine, id, index, dTabWidget, lostPack,
                           totalPack, lostRate, labellossC, passButton);
        }
    }

    return;
}

//Iperf3 进程启动停止后清楚功能
void MainWindow::Iperf3_ClearClicked(const int &index, const QString &dataTableWidget0, const QString &btArgc0, const QString &badTextEdit0)
{
    //Iperf3_ClearClicked(0, "P1_1_TabWidget", "P1_1_CmdArgs", "P1_1_bad");
    QWidget *widget0 = ui->widget_0->widget(1);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_eth");

    QWidget *widget1 = secondTab->widget(index);
    QTableWidget *dataTableWidget = widget1->findChild<QTableWidget*>(dataTableWidget0);
    if( dataTableWidget )
    {
        dataTableWidget->setColumnCount(0);
        dataTableWidget->setRowCount(0);
    }

    QLineEdit *btArgc = widget1->findChild<QLineEdit*>(btArgc0);
    if( btArgc )
        btArgc->clear();

    QTextEdit *badTextEdit = widget1->findChild<QTextEdit*>(badTextEdit0);
    if( badTextEdit )
        badTextEdit->clear();

    QList<QPushButton*> pushButtons = widget1->findChildren<QPushButton*>();
    for (QPushButton* button : pushButtons) {
        if (!button)
            continue;
        button->setStyleSheet("");
        if (button->objectName().endsWith("_TotalPackets"))
            button->setText("0");
    }

    QList<QLabel*> labelList = widget1->findChildren<QLabel*>();
    for (QLabel* label : labelList) {
        if (!label)
            continue;
        if (label->objectName().contains("_Los"))
            label->setText("0");
    }

    return;
}

//void MainWindow::Iperf3_StartorPause_Process(const QString &id, const int &index, const QString &btStart0,const QString &textBad0, const QString &CmdArgs0)
//{
//    qInfo() << "[" << id << "] Iperf3_StartorPause_Process...";
//    //Iperf3_StartorPause_Process("P1_1", 0, "P1_1_Start", "P1_1_bad", "P1_1_CmdArgs");
//    QWidget *widget0 = ui->widget_0->widget(1);
//    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_eth");

//    QWidget *widget1 = secondTab->widget(index);
//    QPushButton *btStart = widget1->findChild<QPushButton*>(btStart0);
//    QTextEdit *textBad = widget1->findChild<QTextEdit*>(textBad0);
//    textBad->setReadOnly(true);
//    textBad->clear();

//    // 检查是否正在运行
//    if (processRunningMap.value(id, false)) {
//        // 停止进程
//        QProcess *iperf3Process = iperf3ProcessMap.value(id, nullptr);
//        if (iperf3Process) {
//            iperf3Process->terminate();
//            if (!iperf3Process->waitForFinished(1000)) {
//                iperf3Process->kill();
//                iperf3Process->waitForFinished();
//            }
//            // 关键修复：手动触发一次finished信号处理
//            onProcessFinished(id, index, iperf3Process->exitCode(), iperf3Process->exitStatus());
//        }
//        processRunningMap[id] = false;
//        btStart->setText("启动");
//        return;
//    }

//    // 检查并发限制
//    if (concurrentSemaphore.available() <= 0) {
//        textBad->setText("超过最大并发数(10个)，请稍后再试");
//        return;
//    }

//    // 获取命令参数
//    QLineEdit *Cmd = secondTab->findChild<QLineEdit*>(CmdArgs0);
//    if (!Cmd) {
//        textBad->setText("未找到命令输入框");
//        return;
//    }

//    QString targetIp = Cmd->text().trimmed();
//    if (targetIp.isEmpty()) {
//        textBad->setText("请输入监测IP和参数（如：iperf3 -c 192.168.1.100 -p 5201 -t 0）");
//        return;
//    }

//    // 解析命令参数
//    QStringList argsList = targetIp.split(" ", QString::SkipEmptyParts);
//    if (argsList.isEmpty()) {
//        textBad->setText("命令格式错误或iperf3路径无效");
//        return;
//    }

//    //创建独立进程
//    QProcess *process = iperf3ProcessMap.value(id, nullptr);
//    if (process) {
//        process->disconnect(); // 断开旧信号，避免干扰
//        delete process;
//    }

//    process = new QProcess(this);
//    process->setProcessChannelMode(QProcess::MergedChannels); // 合并stdout和stderr
//    iperf3ProcessMap[id] = process;

//    //异步监听进程启动结果
//    connect(process, &QProcess::started, this, [=]() {
//        QMutexLocker locker(&runningMapMutex); // 线程安全保护
//        processRunningMap[id] = true;
//        btStart->setText("停止");
//        if (concurrentSemaphore.available() > 0) {
//            concurrentSemaphore.acquire();
//            qInfo() << "[" << id << "] 启动成功！参数：" << argsList;
//            qInfo() << "当前并发数：" << (10 - concurrentSemaphore.available()) << "/10"; // 正确计算方式
//        } else {
//            qWarning() << "[" << id << "] 启动成功但无可用并发名额，可能存在名额泄漏";
//        }
//    });

//    //异步监听进程启动失败
//    connect(process, &QProcess::errorOccurred, this, [=](QProcess::ProcessError error) {
//        QString errorMsg;
//        switch (error) {
//            case QProcess::FailedToStart: errorMsg = "iperf3可执行文件未找到或权限不足"; break;
//            case QProcess::Crashed: errorMsg = "进程启动后崩溃"; break;
//            default: errorMsg = "未知错误：" + process->errorString();
//        }
//        textBad->setText("启动失败：" + errorMsg);
//        qWarning() << "[" << id << "] 启动失败：" << errorMsg;
//        // 清理失败的进程
//        delete process;
//        iperf3ProcessMap.remove(id);
//        btStart->setText("启动"); // 恢复按钮状态
//    });

//    //连接信号
//    connect(process, &QProcess::readyReadStandardOutput, this, [=]() {
//            onIperf3OutputReady(id, index, id + "_TabWidget", id + "_LostPackets",
//                               id + "_TotalPackets", id + "_LossRate",
//                               id + "_LossCount", id + "_Pass");
//        });

//    //捕获服务端启动的初始1行输出（关键！）
//    connect(process, &QProcess::readyReadStandardOutput, this, [=]() {
//        QString output = process->readAllStandardOutput();
//        if (!output.isEmpty()) {
//            textBad->append("启动成功：" + output.trimmed()); // 显示服务端启动日志
//            qInfo() << "[" << id << "] 服务端输出：" << output.trimmed();
//        }
//    });

//    connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
//            this, [=](int exitCode, QProcess::ExitStatus exitStatus){
//        onProcessFinished(id, index, exitCode, exitStatus);
//    });

//    process->start(argsList.first(), argsList.mid(1));

//    return;
//}

void MainWindow::Iperf3_StartorPause_Process(const QString &id, const int &index, const QString &btStart0, const QString &textBad0, const QString &CmdArgs0)
{
    qInfo() << "[" << id << "] Iperf3_StartorPause_Process...";
    // 1. 获取UI控件（保持原逻辑）
    QWidget *widget0 = ui->widget_0->widget(1);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_eth");
    if (!secondTab) {
        qWarning() << "[" << id << "] 未找到 widget_eth 控件";
        return;
    }

    QWidget *widget1 = secondTab->widget(index);
    QPushButton *btStart = widget1->findChild<QPushButton*>(btStart0);
    QTextEdit *textBad = widget1->findChild<QTextEdit*>(textBad0);
    if (!btStart || !textBad) {
        qWarning() << "[" << id << "] 未找到启动按钮或日志文本框";
        return;
    }
    textBad->setReadOnly(true);
    textBad->clear();

    if (processRunningMap.value(id, false)) {
        QProcess *iperf3Process = iperf3ProcessMap.value(id, nullptr);
        if (iperf3Process) {
            // 先断开信号，避免停止时触发多余解析
            iperf3Process->disconnect(this);
            // 优雅终止进程
            iperf3Process->terminate();
            if (!iperf3Process->waitForFinished(1000)) {
                iperf3Process->kill();
                iperf3Process->waitForFinished();
            }
            onProcessFinished(id, index, iperf3Process->exitCode(), iperf3Process->exitStatus());
            // 释放进程对象（避免内存泄漏）
            delete iperf3Process;
            iperf3ProcessMap.remove(id);
        }
        processRunningMap[id] = false;
        btStart->setText("启动");
        concurrentSemaphore.release(); // 释放并发名额（原逻辑可能遗漏）
        return;
    }

    if (concurrentSemaphore.available() <= 0) {
        textBad->setText("超过最大并发数(10个)，请稍后再试");
        return;
    }

    QLineEdit *Cmd = secondTab->findChild<QLineEdit*>(CmdArgs0);
    if (!Cmd) {
        textBad->setText("未找到命令输入框");
        return;
    }

    QString targetCmd = Cmd->text().trimmed();
    if (targetCmd.isEmpty()) {
        textBad->setText("请输入监测命令（如：iperf3 -c 192.168.1.100 -p 5201 -t 0）");
        return;
    }

    QStringList argsList = targetCmd.split(" ", QString::SkipEmptyParts);
    if (argsList.isEmpty()) {
        textBad->setText("命令格式错误");
        return;
    }

    QString program = argsList.first();
    QStringList realArgs = argsList.mid(1);

    program = "stdbuf";
    realArgs.prepend(argsList.first()); // 将原iperf3路径作为stdbuf的参数
    realArgs.prepend("-o0");            // 禁用stdout缓存
    qInfo() << "[" << id << "] Linux/macOS系统：使用 stdbuf -o0 禁用缓存";

    QProcess *process = new QProcess(this);
    process->setProcessChannelMode(QProcess::MergedChannels);
    iperf3ProcessMap[id] = process;

    connect(process, &QProcess::started, this, [=]() {
        QMutexLocker locker(&runningMapMutex);
        processRunningMap[id] = true;
        btStart->setText("停止");
        if (concurrentSemaphore.available() > 0) {
            concurrentSemaphore.acquire();
        }
        // 显示启动成功日志
        QString startLog = QString("[" + id + "] 启动成功！命令：%1 %2")
                           .arg(program).arg(realArgs.join(" "));
        textBad->append(startLog);
        qInfo() << startLog;
    });

    connect(process, &QProcess::errorOccurred, this, [=](QProcess::ProcessError error) {
        QString errorMsg;
        switch (error) {
            case QProcess::FailedToStart:
                errorMsg = "iperf3可执行文件未找到、权限不足或命令错误";
                errorMsg += "\n当前命令：" + program + " " + realArgs.join(" ");
                break;
            case QProcess::Crashed: errorMsg = "进程启动后崩溃"; break;
            default: errorMsg = "未知错误：" + process->errorString();
        }
        textBad->setText("启动失败：" + errorMsg);
        qWarning() << "[" << id << "] 启动失败：" << errorMsg;
        // 清理资源
        processRunningMap[id] = false;
        delete process;
        iperf3ProcessMap.remove(id);
        btStart->setText("启动");
    });

    connect(process, &QProcess::readyReadStandardOutput, this, [=]() {
        QByteArray outputBytes = process->readAllStandardOutput();
        if (outputBytes.isEmpty()) return;

        QString output = QString::fromLocal8Bit(outputBytes);
        QStringList lines = output.split('\n', QString::SkipEmptyParts);

        for (const QString &line : lines) {
            QString trimmedLine = line.trimmed();
            if (trimmedLine.isEmpty()) continue;

            //textBad->append(trimmedLine);
            textBad->verticalScrollBar()->setValue(textBad->verticalScrollBar()->maximum());

            parseIperf3Data(trimmedLine, id, index,
                           id + "_TabWidget",
                           id + "_LostPackets",
                           id + "_TotalPackets",
                           id + "_LossRate",
                           id + "_LossCount",
                           id + "_Pass");
        }
    });

    connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            this, [=](int exitCode, QProcess::ExitStatus exitStatus){
        onProcessFinished(id, index, exitCode, exitStatus);
        // 清理资源
        delete process;
        iperf3ProcessMap.remove(id);
        processRunningMap[id] = false;
        btStart->setText("启动");
        concurrentSemaphore.release(); // 释放并发名额
        textBad->append(QString("[" + id + "] 进程已停止，退出码：%1").arg(exitCode));
    });

    qInfo() << "[" << id << "] 启动进程：" << program << realArgs.join(" ");
    process->start(program, realArgs);
}


void MainWindow::on_P1_1_Start_clicked()
{
    qInfo() << "==================== P1_1 按钮被点击 ====================";
    Iperf3_StartorPause_Process("P1_1", 0, "P1_1_Start", "P1_1_bad", "P1_1_CmdArgs");
}

void MainWindow::on_P1_1_Clear_clicked()
{
    Iperf3_ClearClicked(0, "P1_1_TabWidget", "P1_1_CmdArgs", "P1_1_bad");
}

void MainWindow::on_P1_2_Start_clicked()
{
    qInfo() << "==================== P1_2 按钮被点击 ====================";
    Iperf3_StartorPause_Process("P1_2", 0, "P1_2_Start", "P1_2_bad", "P1_2_CmdArgs");
}

void MainWindow::on_P1_2_Clear_clicked()
{
    Iperf3_ClearClicked(0, "P1_2_TabWidget", "P1_2_CmdArgs", "P1_2_bad");
}

void MainWindow::on_P2_1_Start_clicked()
{
    qInfo() << "==================== P2_1 按钮被点击 ====================";
    Iperf3_StartorPause_Process("P2_1", 1, "P2_1_Start", "P2_1_bad", "P2_1_CmdArgs");
}

void MainWindow::on_P2_1_Clear_clicked()
{
    Iperf3_ClearClicked(1, "P2_1_TabWidget", "P2_1_CmdArgs", "P2_1_bad");
}

void MainWindow::on_P2_2_Start_clicked()
{
    qInfo() << "==================== P2_2 按钮被点击 ====================";
    Iperf3_StartorPause_Process("P2_2", 1, "P2_2_Start", "P2_2_bad", "P2_2_CmdArgs");
}

void MainWindow::on_P2_2_Clear_clicked()
{
    Iperf3_ClearClicked(1, "P2_2_TabWidget", "P2_2_CmdArgs", "P2_2_bad");
}

void MainWindow::on_D2000_1_Start_clicked()
{
    qInfo() << "==================== D2000_1 按钮被点击 ====================";
    Iperf3_StartorPause_Process("D2000_1", 2, "D2000_1_Start", "D2000_1_bad", "D2000_1_CmdArgs");
}

void MainWindow::on_D2000_1_Clear_clicked()
{
    Iperf3_ClearClicked(2, "D2000_1_TabWidget", "D2000_1_CmdArgs", "D2000_1_bad");
}

void MainWindow::on_D2000_2_Start_clicked()
{
    qInfo() << "==================== D2000_2 按钮被点击 ====================";
    Iperf3_StartorPause_Process("D2000_2", 2, "D2000_2_Start", "D2000_2_bad", "D2000_2_CmdArgs");
}

void MainWindow::on_D2000_2_Clear_clicked()
{
    Iperf3_ClearClicked(2, "D2000_2_TabWidget", "D2000_2_CmdArgs", "D2000_2_bad");
}


void MainWindow::on_Computer_1_Start_clicked()
{
    qInfo() << "==================== Computer_1 按钮被点击 ====================";
    Iperf3_StartorPause_Process("Computer_1", 3, "Computer_1_Start", "Computer_1_bad", "Computer_1_CmdArgs");
}

void MainWindow::on_Computer_1_Clear_clicked()
{
    Iperf3_ClearClicked(3, "Computer_1_TabWidget", "Computer_1_CmdArgs", "Computer_1_bad");
}

void MainWindow::on_Computer_2_Start_clicked()
{
    qInfo() << "==================== Computer_2 按钮被点击 ====================";
    Iperf3_StartorPause_Process("Computer_2", 3, "Computer_2_Start", "Computer_2_bad", "Computer_2_CmdArgs");
}

void MainWindow::on_Computer_2_Clear_clicked()
{
    Iperf3_ClearClicked(3, "Computer_2_TabWidget", "Computer_2_CmdArgs", "Computer_2_bad");
}

void MainWindow::on_Computer_3_Start_clicked()
{
    qInfo() << "==================== Computer_3 按钮被点击 ====================";
    Iperf3_StartorPause_Process("Computer_3", 3, "Computer_3_Start", "Computer_3_bad", "Computer_3_CmdArgs");
}

void MainWindow::on_Computer_3_Clear_clicked()
{
    Iperf3_ClearClicked(3, "Computer_3_TabWidget", "Computer_3_CmdArgs", "Computer_3_bad");
}

void MainWindow::on_Computer_4_Start_clicked()
{
    qInfo() << "==================== Computer_4 按钮被点击 ====================";
    Iperf3_StartorPause_Process("Computer_4", 3, "Computer_4_Start", "Computer_4_bad", "Computer_4_CmdArgs");
}

void MainWindow::on_Computer_4_Clear_clicked()
{
    Iperf3_ClearClicked(3, "Computer_4_TabWidget", "Computer_4_CmdArgs", "Computer_4_bad");
}


void MainWindow::onErrorOccurred(const QString& errorMsg)
{
    // 方式2：输出到调试控制台（开发时用）
    qDebug() << "[PCAN信息]:" << errorMsg;

    // 方式3：严重错误时弹窗提示（可选，用于关键错误）
    if (errorMsg.contains("初始化失败") || errorMsg.contains("总线关闭")) {
        QMessageBox::warning(this, "PCAN错误", errorMsg);
    }

}

// 递归重置指定部件及其所有子部件的状态
void MainWindow::resetWidget(QTabWidget *widget)
{
    if (!widget) return;

    // 处理所有按钮：清除样式、恢复启用状态（根据实际需求调整）
    QList<QPushButton*> buttons = widget->findChildren<QPushButton*>();
    foreach (QPushButton* btn, buttons) {
      btn->setStyleSheet(""); // 清除自定义样式
      btn->setEnabled(true); // 假设默认是启用状态，按需修改
      QStringList eButtons = {"PCAN_Start", "PCAN_Close", "Control_Start", "BadStop"};
      if (!eButtons.contains(btn->objectName())) {
              btn->setText("");
          }
    }

    // 处理所有复选框：取消勾选（根据实际默认状态调整）
    QList<QCheckBox*> checkBoxes = widget->findChildren<QCheckBox*>();
    foreach (QCheckBox* cb, checkBoxes) {
      cb->setChecked(false);
    }

    // 处理所有QLabel：清除自定义样式、恢复默认文本（按需添加）
    QList<QLabel*> labels = widget->findChildren<QLabel*>();
    foreach (QLabel* lab, labels) {
      lab->setStyleSheet(""); // 清除自定义样式（如背景色、字体等）
    }

    QList<QComboBox*> comboBoxes = widget->findChildren<QComboBox*>();
    foreach (QComboBox* combo, comboBoxes) {
        combo->setStyleSheet(""); // 清除自定义样式
        combo->setCurrentIndex(0); // 还原到第一个选项（默认初始状态）
        combo->setEnabled(true); // 恢复启用状态（按需调整）
    }

    return;
}

void MainWindow::onConnectionStatusChanged(bool isConnected)
{
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");
    QWidget *widget1 = secondTab->widget(0);
    QPushButton *btStyle = widget1->findChild<QPushButton*>("PCAN_Start");
    if( isConnected ){
        qDebug() << "[设备已连接]";
        btStyle->setStyleSheet("background-color: #7FFF00; color: white;");
    }
    else{
        sendTimer->stop();
        qDebug() << "[设备已断开]";
        resetWidget(secondTab);
    }
}

//设置PCAN 信号灯颜色
void MainWindow::setLightColorsStyle(QWidget *widget1, const QString& sigName, double physValue)
{
    //莹绿色 #7FFF00 黄色 #FFFF00 红色 #FF0000 中深灰 #424242

    QString color = "#424242";
    if( sigName.contains("_State") || sigName.contains("_Startup_Status")
        || sigName.contains("_DI_GP") ){
        color = "#FF0000";
        if( physValue == 1 )
            color = "#7FFF00";
    }
    else {
        color = "#7FFF00";
        if( physValue == 1 )
            color = "#FF0000";
    }

    QString lightSrc = "circleColors_" + sigName;
    QLabel *lightStyle = widget1->findChild<QLabel*>(lightSrc);
    if( lightStyle )
        lightStyle->setStyleSheet("background-color: " + color + "; color: white;");

//    QPushButton *btStyle = widget1->findChild<QPushButton*>(sigName);
//    if (btStyle)
//        btStyle->setStyleSheet("background-color: " + color + "; color: white;");

    return;
}

//PCAN 数据接收 设置配置界面
void MainWindow::setPCANConfigUI(const QString& sigName, double physValue)
{
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

    //配置界面
    QWidget *widget1 = secondTab->widget(0);
    //PCAN_310p_Sw_Version
    QPushButton *configPCAN = widget1->findChild<QPushButton*>("PCAN_" + sigName);
    if( configPCAN )
        configPCAN->setText(QString::number(physValue));
    QPushButton *config = widget1->findChild<QPushButton*>(sigName);
    if( config ){
        QString displayText = "未知";
        if ( sigName == "Cpu_Chip_Model" || sigName == "Npu_Chip_Model" ) {
            const QString chipModel = (sigName == "Cpu_Chip_Model") ? "Phytium D2000/8 E8C" : "310P3";
            if (physValue == 1) {
                displayText = chipModel;
            } else if (physValue == 0) {
                displayText = "预留";
            }
        }
        else if (sigName == "Cpu_Hard_Disk_Capacity" || sigName == "Npu_Hard_Disk_Capacity") {
            switch ((int)physValue) {
                case 1: displayText = "64GB";    break;
                case 2: displayText = "128GB";   break;
                case 3: displayText = "256GB";   break;
                case 4: displayText = "512GB";   break;
                case 5: displayText = "1TB";    break;
            default:    break;
            }
        }
        else {
            displayText = QString::number(physValue);
        }

        config->setText(displayText);
    }
}

//PCAN 数据接收 设置通信及控制界面
void MainWindow::setPCANComControl(const quint32 &msgId, const QString& sigName, double physValue)
{
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

    //通信及控制界面
    QWidget *widget1 = secondTab->widget(1);
    QPushButton *comBad = widget1->findChild<QPushButton*>(sigName);
    if( comBad )
        comBad->setText(QString("%1").arg(physValue));

    QPushButton *comBadPCAN = widget1->findChild<QPushButton*>("PCAN_" + sigName);
    if( comBadPCAN )
        comBadPCAN->setText(QString("%1").arg(physValue));

    //设置报文
    QString comSrc = "message_" + sigName;
    QPushButton *comMes = widget1->findChild<QPushButton*>(comSrc);
    if( comMes )
        comMes->setText(QString("%1").arg(msgId));
    //设置灯状态
    setLightColorsStyle(widget1, sigName, physValue);
}

//PCAN 数据接收 设置系统状态界面
void MainWindow::setPCANSystemStatus(const QString& sigName, double physValue)
{
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

    //系统状态界面
    QWidget *widget1 = secondTab->widget(2);
    QPushButton *Tempera1 = widget1->findChild<QPushButton*>(sigName);
    if( Tempera1 ){
        Tempera1->setText(QString("%1").arg(physValue));
        if( sigName.contains("HS12V_OUT") && sigName.contains("_State") ){
            QPushButton *Tempera2 = widget1->findChild<QPushButton*>("HS12V_OUT_ReciveStatus");
            Tempera2->setText("BVCU_115接收成功");
            Tempera1->setText("低电平");
            if( 1 == physValue )
                Tempera1->setText("高电平");
        }
    }
    QPushButton *TemperaPCAN = widget1->findChild<QPushButton*>("PCAN_" + sigName);
    if( TemperaPCAN ){
        TemperaPCAN->setText(QString("%1").arg(physValue));
    }

    //设置灯状态
    setLightColorsStyle(widget1, sigName, physValue);

}

//PCAN 数据接收 设置电源诊断界面
void MainWindow::setPCANPowerCheck(const quint32 &msgId,const QString& sigName, double physValue)
{
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

    //电源诊断界面
    QWidget *widget1 = secondTab->widget(3);
    QPushButton *PCheck = widget1->findChild<QPushButton*>(sigName);
    if( PCheck ){
        //设置故障
        PCheck->setText(QString("%1").arg(physValue));
        //设置报文
        QString PCheckSrc = "message_" + sigName;
        QPushButton *PCheckMes = widget1->findChild<QPushButton*>(PCheckSrc);
        if( PCheckMes )
            PCheckMes->setText(QString("%1").arg(msgId));
        //设置灯状态
        setLightColorsStyle(widget1, sigName, physValue);
    }
}

// 温度曲线初始化
void MainWindow::inintemperatureCurve()
{
    // 初始化绘图组件（原有代码不变）
    QChart *temperatureChart = new QChart();
    temperatureChart->setTitle("温度实时监控曲线");
    temperatureChart->setAnimationOptions(QChart::NoAnimation);

    QChartView *chartView = new QChartView(temperatureChart);
    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->setInteractive(true);
    chartView->setRubberBand(QChartView::RectangleRubberBand);

    // ===================== 1. 放大/缩小/还原按钮 =====================
    QPushButton *btnZoomIn = new QPushButton("放大");
    QPushButton *btnZoomOut = new QPushButton("缩小");
    QPushButton *btnResetZoom = new QPushButton("还原");

    btnZoomIn->setFixedSize(40, 30);
    btnZoomOut->setFixedSize(40, 30);
    btnResetZoom->setFixedSize(40, 30);
    QString btnStyle = "QPushButton { background: #f0f0f0; border: 1px solid #ccc; border-radius: 3px; font-size: 12px; }"
                      "QPushButton:hover { background: #e0e0e0; }";
    btnZoomIn->setStyleSheet(btnStyle);
    btnZoomOut->setStyleSheet(btnStyle);
    btnResetZoom->setStyleSheet(btnStyle);

    QWidget *btnContainer = new QWidget(chartView);
    btnContainer->setStyleSheet("background: transparent;");
    QHBoxLayout *btnLayout = new QHBoxLayout(btnContainer);
    btnLayout->addWidget(btnZoomIn);
    btnLayout->addWidget(btnZoomOut);
    btnLayout->addWidget(btnResetZoom);
    btnLayout->setContentsMargins(5, 5, 5, 5);
    btnContainer->setLayout(btnLayout);

    QVBoxLayout *chartLayout = new QVBoxLayout(chartView);
    chartLayout->setContentsMargins(0, 0, 0, 0);
    QHBoxLayout *topRightLayout = new QHBoxLayout();
    topRightLayout->addStretch();
    topRightLayout->addWidget(btnContainer);
    chartLayout->addLayout(topRightLayout);
    chartLayout->addStretch();
    chartView->setLayout(chartLayout);
    // ==================================================================

    // 将图表添加到界面
    QWidget *widgetTemper = ui->widget_0->widget(4);
    QVBoxLayout *layout = widgetTemper->findChild<QVBoxLayout*>("verticalLayout");
    if (layout) {
        layout->addWidget(chartView);
    } else {
        layout = new QVBoxLayout(widgetTemper);
        layout->addWidget(chartView);
        widgetTemper->setLayout(layout);
    }

    // 创建坐标轴
    QValueAxis *axisX = new QValueAxis(); // X轴（时间）
    QValueAxis *axisY = new QValueAxis(); // Y轴（温度）
    axisX->setMin(0);
    axisY->setMin(0);
    axisX->setTitleText("时间 (秒)");
    axisY->setTitleText("温度 (°C)");
    axisX->setLabelFormat("%.1f");
    axisY->setLabelFormat("%.1f");
    temperatureChart->addAxis(axisX, Qt::AlignBottom);
    temperatureChart->addAxis(axisY, Qt::AlignLeft);

    // 创建温度曲线（原有代码不变）
    QStringList tempSigNames = {
        "D2000 CPU温度", "310P NPU温度", "FPGA温度",
        "D2000 NTC温度", "310P NTC温度", "FPGA NTC温度", "PCBA NTC温度"
    };
    QVector<QColor> colors = {Qt::red, Qt::blue, Qt::green, Qt::cyan, Qt::magenta, Qt::yellow, Qt::gray};
    for (int i = 0; i < tempSigNames.size(); ++i) {
        QLineSeries *series = new QLineSeries();
        series->setName(tempSigNames[i]);
        series->setPen(QPen(colors[i], 2));
        temperatureChart->addSeries(series);
        series->attachAxis(axisX);
        series->attachAxis(axisY);
        timeDataMap[tempSigNames[i]] = QVector<double>();
        valueDataMap[tempSigNames[i]] = QVector<double>();
        seriesMap[tempSigNames[i]] = series;
    }

    // 声明初始化范围变量
    qreal initXMin, initXMax, initYMin, initYMax;

    // 测试数据
//    startTime = QDateTime::currentMSecsSinceEpoch();
//    setCurrTemperatCurve("D2000_Cpu_Tempera", 30);
//    setCurrTemperatCurve("D2000_Cpu_Tempera", -10);
//    setCurrTemperatCurve("D2000_Cpu_Tempera", 70);
//    setCurrTemperatCurve("D2000_Cpu_Tempera", 100);
//    setCurrTemperatCurve("Fpga_Tempera", 0);
//    setCurrTemperatCurve("Fpga_Tempera", -20);
//    setCurrTemperatCurve("Fpga_Tempera", 70);
//    setCurrTemperatCurve("Fpga_Tempera", 10);

    // 保存初始范围（移至测试数据之后，确保获取正确的初始范围）
    initXMin = axisX->min();
    initXMax = axisX->max();
    initYMin = axisY->min();
    initYMax = axisY->max();

    // 1. 创建PWM文本项
    QGraphicsTextItem *pwmTextItem = new QGraphicsTextItem("PWM值: --%");
    QFont font = pwmTextItem->font();
    font.setPointSize(10);
    font.setBold(true);
    pwmTextItem->setFont(font);
    pwmTextItem->setDefaultTextColor(Qt::darkMagenta);
    pwmInfoItem = pwmTextItem;

    // 2. 添加到图表场景
    temperatureChart->scene()->addItem(pwmTextItem);

    // 3. 定义位置更新函数
    auto updatePwmPosition = [=]() {
        if (!pwmInfoItem || !chartView) return;

        // 固定在视图左上角（距离左边和顶部各10像素）
        QPoint viewPos(10, 10);
        // 转换为场景坐标
        QPointF scenePos = chartView->mapToScene(viewPos);
        pwmInfoItem->setPos(scenePos);
    };

    // 确保在图表完全渲染后再计算位置
    QTimer::singleShot(100, this, [=]() {
        updatePwmPosition();
    });

    // 6. 监听所有可能影响位置的事件，保持位置固定
    connect(btnZoomOut, &QPushButton::clicked, this, [=]() {
        if (!axisX || !axisY) return;
        qreal xMin = axisX->min(), xMax = axisX->max();
        qreal yMin = axisY->min(), yMax = axisY->max();
        qreal xRange = (xMax - xMin) * 0.2;
        qreal yRange = (yMax - yMin) * 0.2;
        axisX->setRange(xMin + xRange, xMax - xRange);
        axisY->setRange(yMin + yRange, yMax - yRange);
        // 更新PWM位置
        updatePwmPosition();
    });

    connect(btnZoomIn, &QPushButton::clicked, this, [=]() {
        if (!axisX || !axisY) return;
        qreal xMin = axisX->min(), xMax = axisX->max();
        qreal yMin = axisY->min(), yMax = axisY->max();
        qreal xRange = (xMax - xMin) * 0.2;
        qreal yRange = (yMax - yMin) * 0.2;
        axisX->setRange(xMin - xRange, xMax + xRange);
        axisY->setRange(yMin - yRange, yMax + yRange);
        // 更新PWM位置
        updatePwmPosition();
    });

    connect(btnResetZoom, &QPushButton::clicked, this, [=]() {
        if (!axisX || !axisY) return;
        axisX->setRange(initXMin, initXMax);
        axisY->setRange(initYMin, initYMax);
        // 更新PWM位置
        updatePwmPosition();
    });

    // 7. 监听滚动事件
    connect(chartView->horizontalScrollBar(), &QScrollBar::valueChanged, this, updatePwmPosition);
    connect(chartView->verticalScrollBar(), &QScrollBar::valueChanged, this, updatePwmPosition);

    temperatureChart->legend()->setVisible(true);
    temperatureChart->legend()->setAlignment(Qt::AlignBottom);

    return;
}



// 实时更新PWM值的实现
void MainWindow::updatePWMValue()
{
    if (!pwmInfoItem) {
        qWarning() << "PWM标签未初始化，无法更新PWM值！";
        return;
    }

    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

    //配置界面
    QWidget *widget1 = secondTab->widget(0);

    QComboBox *comboBox = widget1->findChild<QComboBox*>("Fan_Ctrl_En");
    QSpinBox *spinBox = widget1->findChild<QSpinBox*>("Fan_Pwm_Duty");

    int validPwm = 0;  // 限制在0~100之间
    if( comboBox->currentData().toInt() == 1 )
        validPwm = spinBox->value();

    pwmInfoItem->setPlainText(QString("PWM值: %1%").arg(validPwm));

    if (validPwm > 70) {
        pwmInfoItem->setDefaultTextColor(Qt::red);       // 高占空比（红色警告）
    } else if (validPwm > 30) {
        pwmInfoItem->setDefaultTextColor(QColor(255, 165, 0));    // 中占空比（橙色提示）
    } else {
        pwmInfoItem->setDefaultTextColor(Qt::darkGreen); // 低占空比（绿色正常）
    }

    return;
}


//void MainWindow::setCurrTemperatCurve(const QString& sigName, double physValue)
//{

//    QMap<QString, QString> tempIdToNameMap = {
//        {"D2000_Cpu_Tempera", "D2000 CPU温度"},
//        {"310p_Npu_Tempera", "310P NPU温度"},
//        {"Fpga_Tempera", "FPGA温度"},
//        {"D2000_NTC_Tempera", "D2000 NTC温度"},
//        {"A310P_NTC_Tempera", "310P NTC温度"},
//        {"Fpga_NTC_Tempera", "FPGA NTC温度"},
//        {"PCBA_NTC_Tempera", "PCBA NTC温度"}
//    };

//    QString currentSigId = sigName;
//    if ( !tempIdToNameMap.contains(currentSigId) )
//        return;

//    updatePWMValue();  // 实时设置PWM值

//    // 通过ID获取对应的中文显示名称
//    QString tempName = tempIdToNameMap[currentSigId];

//    // 计算相对时间（转换为秒）
//    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
//    double relativeTime = (currentTime - startTime) / 1000.0;

//    // 添加时间和温度值到对应信号的数据容器
//    timeDataMap[tempName].append(relativeTime);
//    valueDataMap[tempName].append(physValue);

//    // 限制数据点数量，防止内存占用过大
//    const int MAX_DATA_POINTS = 1000;
//    if (timeDataMap[tempName].size() > MAX_DATA_POINTS) {
//        timeDataMap[tempName].removeFirst();
//        valueDataMap[tempName].removeFirst();
//    }

//    // 获取对应曲线并更新数据
//    QLineSeries *series = seriesMap[tempName];
//    if (series) {
//        series->clear();
//        for (int i = 0; i < timeDataMap[tempName].size(); ++i) {
//            series->append(timeDataMap[tempName][i], valueDataMap[tempName][i]);
//        }

//        // 自动调整坐标轴范围
//        QValueAxis *axisX = qobject_cast<QValueAxis*>(temperaturePlot->axisX(series));
//        QValueAxis *axisY = qobject_cast<QValueAxis*>(temperaturePlot->axisY(series));
//        if (axisX && axisY) {
//            // X轴范围调整
//            if (!timeDataMap[tempName].isEmpty()) {
//                double xMin = timeDataMap[tempName].first();
//                double xMax = timeDataMap[tempName].last();
//                axisX->setRange(xMin - 1, xMax + 1);  // 固定边距
//            }

//            // Y轴范围调整（考虑所有温度信号的最值）
//            double yMin = 0, yMax = 0;
//            bool first = true;
//            foreach (const QString &name, tempIdToNameMap.values()) {
//                if (!valueDataMap[name].isEmpty()) {
//                    double currentMin = *std::min_element(valueDataMap[name].begin(), valueDataMap[name].end());
//                    double currentMax = *std::max_element(valueDataMap[name].begin(), valueDataMap[name].end());
//                    if (first) {
//                        yMin = currentMin;
//                        yMax = currentMax;
//                        first = false;
//                    } else {
//                        yMin = qMin(yMin, currentMin);
//                        yMax = qMax(yMax, currentMax);
//                    }
//                }
//            }
//            if (!first) {
//                axisY->setRange(yMin - 2, yMax + 2);  // 固定边距
//            }
//        }
//    }

//    return;
//}

void MainWindow::setCurrTemperatCurve(const QString& sigName, double physValue)
{
    static const QMap<QString, QString> tempIdToNameMap = {
        {"D2000_Cpu_Tempera", "D2000 CPU温度"},
        {"310p_Npu_Tempera", "310P NPU温度"},
        {"Fpga_Tempera", "FPGA温度"},
        {"D2000_NTC_Tempera", "D2000 NTC温度"},
        {"A310P_NTC_Tempera", "310P NTC温度"},
        {"Fpga_NTC_Tempera", "FPGA NTC温度"},
        {"PCBA_NTC_Tempera", "PCBA NTC温度"}
    };

    if (!tempIdToNameMap.contains(sigName))
        return;

    updatePWMValue();  // 实时设置PWM值

    QString tempName = tempIdToNameMap[(sigName)];
    const int MAX_DATA_POINTS = 1000;

    qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
    double relativeTime = (currentTime - startTime) / 1000.0;

    QVector<double>& timeData = timeDataMap[tempName];
    QVector<double>& valueData = valueDataMap[tempName];

    timeData.append(relativeTime);
    valueData.append(physValue);

    if (timeData.size() > MAX_DATA_POINTS) {
        timeData.removeFirst();
        valueData.removeFirst();
    }

    QLineSeries* series = seriesMap[tempName];
    if (!series) return;

    if (timeData.size() > 0) {
        if (timeData.size() == 1) {
            series->clear();
            series->append(timeData[0], valueData[0]);
        } else {
            series->append(timeData.last(), valueData.last());
            if (series->count() > MAX_DATA_POINTS) {
                series->remove(0);
            }
        }
    }

    QValueAxis* axisX = qobject_cast<QValueAxis*>(temperaturePlot->axisX(series));
    QValueAxis* axisY = qobject_cast<QValueAxis*>(temperaturePlot->axisY(series));
    if (!axisX || !axisY) return;

    if (!timeData.isEmpty()) {
        double xMin = timeData.first();
        double xMax = timeData.last();
        if (qAbs(axisX->min() - (xMin - 1)) > 0.5 ||
            qAbs(axisX->max() - (xMax + 1)) > 0.5) {
            axisX->setRange(xMin - 1, xMax + 1);
        }
    }

    static qint64 lastYUpdateTime = 0;
    qint64 now = QDateTime::currentMSecsSinceEpoch();
    if (now - lastYUpdateTime > 500) {
        lastYUpdateTime = now;

        double yMin = 0, yMax = 0;
        bool first = true;
        for (auto it = tempIdToNameMap.constBegin(); it != tempIdToNameMap.constEnd(); ++it) {
            const QString& name = it.value();
            const QVector<double>& values = valueDataMap[name];
            if (values.isEmpty()) continue;
            auto minVal = *std::min_element(values.begin(), values.end());
            auto maxVal = *std::max_element(values.begin(), values.end());

            if (first) {
                yMin = minVal;
                yMax = maxVal;
                first = false;
            } else {
                yMin = qMin(yMin, minVal);
                yMax = qMax(yMax, maxVal);
            }
        }

        if (!first) {
            if (qAbs(axisY->min() - (yMin - 2)) > 0.5 ||
                qAbs(axisY->max() - (yMax + 2)) > 0.5) {
                axisY->setRange(yMin - 2, yMax + 2);
            }
        }
    }
}


// 接收信号的处理函数
void MainWindow::onSignalReceived(const QString& msgName, quint32 msgId, const QByteArray& data,
                                  const QString& sigName, double physValue, const QString& valueDesc)
{
    // 更新UI或处理数据
    qDebug() << "MainWindow::onSignalReceived" << msgName<< ":" << msgId<< ":" << data << ":"
             << sigName << "=" << physValue << valueDesc;

    ++ReciveNum;
    ++ReciveFD_Success;

    // QStringList sigNameLists = {"Cpu_Can1_Com_State", "Cpu_Can2_Com_State", "Cpu_Can3_Com_State",
    //                            "Cpu_Can4_Com_State", "Cpu_Can5_Com_State"};
    // if ( sigNameLists.contains(msgName) ){
        qint64 currentTime = QDateTime::currentMSecsSinceEpoch();
        if (!lastMsgIdReceiveTime.contains(msgId)) {
               qDebug() << "[MSGID初始化] 首次接收CAN报文ID:" << msgId << "（" << msgName << "），初始化计数与时间戳";
               lastMsgIdReceiveTime[msgId] = currentTime;
               msgIdTimeoutCount[msgId] = 0;
        } else {
           // 3. 非首次接收：计算时间差
           qint64 lastTime = lastMsgIdReceiveTime[msgId];
           qint64 timeDiff = currentTime - lastTime;  // 时间差（毫秒）

           // 4. 判断是否超过1秒（1000毫秒）
           if (timeDiff > MSGID_TIMEOUT_THRESHOLD) {
               msgIdTimeoutCount[msgId]++;
               qWarning() << "[MSGID超时] CAN报文ID:" << msgId << "（" << msgName << "）"
                          << "接收间隔" << timeDiff << "ms（>1s），累计超时次数：" << msgIdTimeoutCount[msgId];
           } else {
               qDebug() << "[MSGID正常] CAN报文ID:" << msgId << "（" << msgName << "）"
                        << "接收间隔" << timeDiff << "ms（≤1s），当前超时次数：" << msgIdTimeoutCount[msgId];
           }
           lastMsgIdReceiveTime[msgId] = currentTime;
        }

        //MCU_41_ "+" Cpu_Can1_Com_State
        setPCANComControl(0, QString("%1_%2").arg(msgName, sigName), msgIdTimeoutCount[msgId]);
   // }

    //PCAN 数据接收 设置配置界面
    setPCANConfigUI("ReciveNum", ReciveNum);
    setPCANConfigUI("ReciveFD_Success", ReciveFD_Success);
    setPCANConfigUI(sigName, physValue);
    //PCAN 数据接收 设置通信及控制界面
    setPCANComControl(msgId, sigName, physValue);
    //PCAN 数据接收 设置系统状态界面
    setPCANSystemStatus(sigName, physValue);
    //PCAN 数据接收 设置电源诊断界面
    setPCANPowerCheck(msgId, sigName, physValue);
    // 记录接收的数据到ASC文件
    if (canLogger && PCANlog) {
        canLogger->logReceivedData(msgId, data, msgName, sigName, physValue, valueDesc);
    }

    // 处理时间戳，判断时间差
//    QStringList sigNameList = {"MCU_PPS_Update_Time", "D2000_PPS_Update_Time", "310P_PPS_Update_Time"};
//    if ( sigNameList.contains(msgName) ) {
//        // 毫秒级时间戳（若为秒级，需乘以1000转换）
//        qint64 currentTime = static_cast<qint64>(physValue);
//        qint64 lastTime = lastTimestampMap[msgName];

//        if (lastTime != -1) {
//            qint64 timeDiff = currentTime - lastTime;
//            bool isWithinRange = (timeDiff >= TIME_THRESHOLD_LOW && timeDiff <= TIME_THRESHOLD_HIGH);

//            physValue = 1;          //设置红色
//            if( isWithinRange )
//                physValue = 0;      //设置绿色

//            qDebug() << "报文" << msgName << "信号:" << sigName << "时间差：" << timeDiff << "ms，"
//                     << (isWithinRange ? "在1s±100ms范围内" : "超出1s±100ms范围")
//                     << ",标识" << physValue;
//            //PCAN 数据接收 设置系统状态界面
//            setPCANSystemStatus(sigName, physValue);
//        }

//        // 更新上一帧时间戳
//        lastTimestampMap[msgName] = currentTime;
//    }

    // 处理温度信号，更新曲线
    //setCurrTemperatCurve(sigName, physValue);

    return;
}

//发送 CPU_51 信号设置
void MainWindow::sendPCANCPU_51(QMap<QString, QVariant> &signalValues)
{
    qInfo() << "开始获取CPU_51报文设置...";
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

//    //系统状态界面
//    QWidget *widget1 = secondTab->widget(2);
//      //高边输出通道 使能控制
//    QGroupBox *groupOut = widget1->findChild<QGroupBox*>("HighSideOutChannel");
//    QComboBox *hsos1 = groupOut->findChild<QComboBox*>("HSOHCnotrol1");
//    QComboBox *hsos2 = groupOut->findChild<QComboBox*>("HSOHCnotrol2");
//    QComboBox *hsos3 = groupOut->findChild<QComboBox*>("HSOHCnotrol3");
//    QComboBox *hsos4 = groupOut->findChild<QComboBox*>("HSOHCnotrol4");

    //通信及控制
    QWidget *widget1 = secondTab->widget(1);
    //高边输出通道 使能控制
    QGroupBox *groupOut = widget1->findChild<QGroupBox*>("controls");
    QComboBox *ConCheck = groupOut->findChild<QComboBox*>("Control_Start_Check");
    if( 1 == ConCheck->currentIndex() ) //自动控制
    {
        if( HLPowerFlag ){
            HLPowerFlag = false;
            HLOutTimer->start();
        }
        qInfo() << "PCAN 发送CPU_51报文，自动控制高低电平信号值: " << HLPower;
        signalValues["HS12V_OUT1_En"] = HLPower;
        signalValues["HS12V_OUT2_En"] = HLPower;
        signalValues["HS12V_OUT3_En"] = HLPower;
        signalValues["HS12V_OUT4_En"] = HLPower;
    }
    else //手动控制
    {
        HLPowerFlag = true;
        HLOutTimer->stop();
        QComboBox *hsos1 = groupOut->findChild<QComboBox*>("HSOHCnotrol1");
        QComboBox *hsos2 = groupOut->findChild<QComboBox*>("HSOHCnotrol2");
        QComboBox *hsos3 = groupOut->findChild<QComboBox*>("HSOHCnotrol3");
        QComboBox *hsos4 = groupOut->findChild<QComboBox*>("HSOHCnotrol4");

        signalValues["HS12V_OUT1_En"] = hsos1->currentIndex();
        signalValues["HS12V_OUT2_En"] = hsos2->currentIndex();
        signalValues["HS12V_OUT3_En"] = hsos3->currentIndex();
        signalValues["HS12V_OUT4_En"] = hsos4->currentIndex();
    }

//    qInfo() << "sendPCANCPU_51 HSOHCnotrol: " << hsos1->currentIndex() << " "<< hsos2->currentIndex()
//            << " "<< hsos3->currentIndex() << " "<< hsos4->currentIndex() << " ";

    //配置界面
    QWidget *widget2 = secondTab->widget(0);
    //风冷控制
    QGroupBox *groupOut2 = widget2->findChild<QGroupBox*>("airControl");
    QComboBox *Fan_Ctrl_En = groupOut2->findChild<QComboBox*>("Fan_Ctrl_En");
    QSpinBox *Fan_Pwm_Duty = groupOut2->findChild<QSpinBox*>("Fan_Pwm_Duty");
    signalValues["Fan_Ctrl_En"] = Fan_Ctrl_En->currentIndex();
    signalValues["Fan_Pwm_Duty"] = Fan_Pwm_Duty->value();
    qInfo() << "sendPCANCPU_51 风扇控制信息: " << Fan_Ctrl_En->currentIndex() << " "<< Fan_Pwm_Duty->value() << " ";

    //电源控制 internalPowerControl
    QGroupBox *groupOut3 = widget2->findChild<QGroupBox*>("internalPowerControl");
    QComboBox *Power_Ctrl_En = groupOut3->findChild<QComboBox*>("Power_Ctrl_En");
    QComboBox *D2000_Pwr_En = groupOut3->findChild<QComboBox*>("D2000_Pwr_En");
    QComboBox *A310p_Pwr_En = groupOut3->findChild<QComboBox*>("A310p_Pwr_En");
    QComboBox *Switch_Phy_Pwr_En = groupOut3->findChild<QComboBox*>("Switch_Phy_Pwr_En");
    QComboBox *Vcc11v0_Gmsl_En = groupOut3->findChild<QComboBox*>("Vcc11v0_Gmsl_En");
    QComboBox *Vcc3v3_Osc_En = groupOut3->findChild<QComboBox*>("Vcc3v3_Osc_En");
    QComboBox *Vcc5v0_Fpga_Pwr_En = groupOut3->findChild<QComboBox*>("Vcc5v0_Fpga_Pwr_En");
    signalValues["Power_Ctrl_En"] = Power_Ctrl_En->currentIndex();
    signalValues["D2000_Pwr_En"] = D2000_Pwr_En->currentIndex();
    signalValues["A310p_Pwr_En"] = A310p_Pwr_En->currentIndex();
    signalValues["Switch_Phy_Pwr_En"] = Switch_Phy_Pwr_En->currentIndex();
    signalValues["Vcc11v0_Gmsl_En"] = Vcc11v0_Gmsl_En->currentIndex();
    signalValues["Vcc3v3_Osc_En"] = Vcc3v3_Osc_En->currentIndex();
    signalValues["Vcc5v0_Fpga_Pwr_En"] = Vcc5v0_Fpga_Pwr_En->currentIndex();

//    qInfo() << "sendPCANCPU_51 IPowerCnotrol: " << Power_Ctrl_En->currentIndex() << " "<< D2000_Pwr_En->currentIndex()
//            << " "<< A310p_Pwr_En->currentIndex() << " "<< Switch_Phy_Pwr_En->currentIndex() << " "
//               << " "<< Vcc11v0_Gmsl_En->currentIndex() << " "<< Vcc3v3_Osc_En->currentIndex() << " "
//                  << " "<< Vcc5v0_Fpga_Pwr_En->currentIndex() << " ";

    qInfo() << "结束获取CPU_51报文设置...";
    return;
}

//发送 BVCU_115 信号设置
void MainWindow::sendPCANBVCU_115(QMap<QString, QVariant> &signalValues)
{
    qInfo() << "开始获取BVCU_115报文设置...";
    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

    //系统状态界面
    QWidget *widget1 = secondTab->widget(2);
    QGroupBox *groupOut = widget1->findChild<QGroupBox*>("HighSideOutChannel");
    QComboBox *hsos1 = groupOut->findChild<QComboBox*>("HSOHAcq1");
    QComboBox *hsos2 = groupOut->findChild<QComboBox*>("HSOHAcq2");
    QComboBox *hsos3 = groupOut->findChild<QComboBox*>("HSOHAcq3");
    QComboBox *hsos4 = groupOut->findChild<QComboBox*>("HSOHAcq4");

    signalValues["HS12V_OUT1_State"] = hsos1->currentIndex();
    signalValues["HS12V_OUT2_State"] = hsos2->currentIndex();
    signalValues["HS12V_OUT3_State"] = hsos3->currentIndex();
    signalValues["HS12V_OUT4_State"] = hsos4->currentIndex();

//    qInfo() << "sendPCANBVCU_115 HSOHAcq: " << hsos1->currentIndex() << " "<< hsos2->currentIndex()
//            << " "<< hsos3->currentIndex() << " "<< hsos4->currentIndex() << " ";

    qInfo() << "结束获取BVCU_115报文设置...";
}

// PCAN 发送报文
void MainWindow::onSendCanMessages()
{
    qInfo() << "开始 定时发送PCAN报文..." << endl;
    // 检查CAN连接状态
    if (!pcanReceiver || !pcanReceiver->isConnected()) {
        qInfo() << "MainWindow::onSendCanMessages: 发送数据时设备未连接";
        return;
    }

    // 获取所有报文名称（从配置中读取）
    QStringList msgNames = m_canProtManager->getMessageNames();
    if (msgNames.isEmpty()) {
        qInfo() << "没有可发送的CAN报文配置";
        return;
    }

    // 遍历每个报文，生成数据并发送
    foreach (const QString& msgName, msgNames) {
        ++SendNum;
        setPCANConfigUI("SendNum", SendNum);
        // 1. 获取报文配置（包含ID、长度等信息）
        MessageConfig msgConfig = m_canProtManager->getMessageConfig(msgName);
        if (msgConfig.name.isEmpty()) {
            qInfo() << "报文" << msgName << "配置无效，跳过发送";
            continue;
        }

        qInfo() << "定时发送报文 名称：" << msgConfig.name << "ID: " << msgConfig.id;
        // 2. 生成报文数据（自动处理初始值、循环计数器、校验和）
        // 若需自定义信号值，可在QMap中添加（如signalValues["HS12V_OUT1_State"] = 1）
        QMap<QString, QVariant> signalValues; // 空表示使用初始值
//        if( msgConfig.name == "BVCU_115" )      //获取 BVCU_115 报文设置
//            sendPCANBVCU_115(signalValues);
        if( msgConfig.name == "CPU_51" )    //获取 CPU_51 报文设置
            sendPCANCPU_51(signalValues);

        QByteArray sendData = m_canProtManager->generateMessageData(msgName, signalValues);
        if (sendData.isEmpty()) {
            qInfo() << "报文" << msgName << "数据生成失败，跳过发送";
            continue;
        }

        // 3. 转换报文ID（字符串"0x56" -> 整数0x56）
        bool ok;
        quint32 canId = msgConfig.id.toUInt(&ok, 16); // 16进制转换
        if (!ok) {
            qWarning() << "报文" << msgName << "ID格式错误:" << msgConfig.id;
            continue;
        }

        // 4. 发送CAN数据
        bool sendSuccess = pcanReceiver->sendCanData(canId, sendData);

        // 5. 记录日志
        if ( sendSuccess ) {
            ++SendFD_Success;
            setPCANConfigUI("SendFD_Success", SendFD_Success);
            if( canLogger && PCANlog )
                canLogger->logSentData(canId, sendData, msgName);
        }
        else{
            qWarning() << "报文" << msgName << "发送失败 (ID: 0x"
                      << QString::number(canId, 16).toUpper() << ")";
        }
    }
    qInfo() << "结束 定时发送PCAN报文..." << endl;
}


void MainWindow::on_PCAN_Start_clicked()
{
    qInfo() << "启动PCAN设备";

    // 加载JSON配置文件（注意文件路径需正确）
    bool isConfigLoaded = m_canProtManager->loadConfig(QString(PROJECT_DIR) + "/SendCANConfig.json");
    if (!isConfigLoaded) {
        qWarning() << "CAN配置文件加载失败，无法发送报文";
        return;
    }

    // 确保日志文件已初始化
    if (PCANlog && !canLogger->initLogFile(ascPath)) {
        qWarning() << "无法初始化日志文件，无法记录数据";
        return;
    }

    // 创建PCAN接收器实例
    pcanReceiver = new PCANReceiver();

    // 连接信号槽
    bool isConnected = connect(pcanReceiver, &PCANReceiver::signalReceived,
            this, &MainWindow::onSignalReceived);
    connect(pcanReceiver, &PCANReceiver::errorOccurred,
            this, &MainWindow::onErrorOccurred);
    connect(pcanReceiver, &PCANReceiver::connectionStatusChanged,
            this, &MainWindow::onConnectionStatusChanged);

    // 初始化设备并加载配置
    QString confFile = QString(PROJECT_DIR) + "/RecvCANConfig.json";
    bool success = pcanReceiver->init(confFile,
                                     PCAN_USBBUS1,  // 使用的CAN总线 PCAN-USB
                                     PCAN_BAUD_500K); // 波特率 500 kBit/sec
    if (success) {
        // 开始接收数据
        pcanReceiver->startReceiving();

        // 启动定时发送
        sendTimer->start();
        qInfo() << "PCAN发送数据 定时器状态：" << (sendTimer->isActive() ? "运行中" : "未运行");
    }
}

void MainWindow::on_PCAN_Close_clicked()
{
    if( pcanReceiver ){
        pcanReceiver->disconnectDevice();

        delete pcanReceiver;
        pcanReceiver = nullptr;
    }

    // 关闭日志文件（可选，也可以在程序退出时关闭）
    if (PCANlog && canLogger) {
       canLogger->closeLogFile();
    }

    // 停止定时器
    sendTimer->stop();

    QWidget *widget0 = ui->widget_0->widget(0);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");
    resetWidget(secondTab);
}


//void MainWindow::on_Control_Start_clicked()
//{
//    SendNum = 0;
//    SendFD_Success = 0;

//    QWidget *widget0 = ui->widget_0->widget(0);
//    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("widget_can");

//    //系统控制界面
//    QWidget *widget1 = secondTab->widget(1);
//    //高边输出通道 使能控制
//    QGroupBox *groupOut = widget1->findChild<QGroupBox*>("controls");
//    QComboBox *ConCheck = groupOut->findChild<QComboBox*>("Control_Start_Check");
//    qInfo() << "发送PCAN数据控制模式：" << ConCheck->currentIndex() << "(0 手动控制 1 自动控制)";
//    if( 1 == ConCheck->currentIndex() ){
//        // 启动定时发送
//        sendTimer->start();
//        qInfo() << "PCAN发送数据 定时器状态：" << (sendTimer->isActive() ? "运行中" : "未运行");
//    }
//    else {
//        onSendCanMessages();
//    }
//}



void MainWindow::initSerialManagers()
{
    // 创建四个串口管理器实例
    m_serialPorts["MCU_232"] = new SerialPortManager(false, this);
    m_serialPorts["RS485"] = new SerialPortManager(false, this);
    m_serialPorts["RS422"] = new SerialPortManager(false, this);
    m_serialPorts["GPRMC"] = new SerialPortManager(false, this);
    m_serialPorts["RS485_2"] = new SerialPortManager(true, this);

    QWidget *widget0 = ui->widget_0->widget(2);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("serialPorts");

    // 连接信号槽
    for (const auto& key : m_serialPorts.keys())
    {
        auto port = m_serialPorts[key];
        QComboBox *comBoxs = secondTab->findChild<QComboBox*>(key);
        QStringList ports = port->scanAvailablePorts();
        foreach (const QString &p, ports) {  // Qt 风格遍历
            qDebug() << "  -" << p;
        }
        //ports << "ttyUSBX" << "/dev/pts/1";
        comBoxs->addItems(ports);

        if (port) {
            if (key != "GPRMC") {
                connect(port, &SerialPortManager::dataReceived,
                        this, &MainWindow::handleDataReceived);
            }
            connect(port, &SerialPortManager::portStatusChanged,
                    this, &MainWindow::handlePortStatusChanged);
        }
    }
}

bool MainWindow::getSerialConfig(const int &index, const QString &serialPort, QString &portName, qint32 &baudRate,
                               QSerialPort::DataBits &dataBits,
                               QSerialPort::Parity &parity,
                               QSerialPort::StopBits &stopBits)
{
    QWidget *widget0 = ui->widget_0->widget(2);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("serialPorts");
    //串口号
    //portName = secondTab->findChild<QPushButton*>(serialPort)->text();
    portName = secondTab->findChild<QComboBox*>(serialPort)->currentText();
    //波特率
    baudRate = secondTab->findChild<QComboBox*>(serialPort + "_baudRate")->currentText().toInt();
    //数据位
    dataBits = static_cast<QSerialPort::DataBits>(secondTab->findChild<QComboBox*>(serialPort + "_dataBit")->currentIndex() + 5);
    //校验方式
    QComboBox *checkBitBox = secondTab->findChild<QComboBox*>(serialPort + "_checkBit");
    int checkBitIndex = checkBitBox->currentIndex();
    if (checkBitIndex < 0 || checkBitIndex > 4) {
        qWarning() << "[getSerialConfig] 校验位索引无效：" << checkBitIndex;
        parity = QSerialPort::NoParity;
    } else {
        parity = static_cast<QSerialPort::Parity>(checkBitIndex);
    }

    //停止位
    QComboBox *stopBitBox = secondTab->findChild<QComboBox*>(serialPort + "_stopBit");
    int stopBitIndex = stopBitBox->currentIndex();
        // 过滤无效索引（仅允许0-2，对应1/1.5/2位停止位）
    switch (stopBitIndex) {
        case 0:
            stopBits = QSerialPort::OneStop;        //1 位停止位
            break;
        case 1:
            stopBits = QSerialPort::OneAndHalfStop; //1.5 位停止位
            break;
        case 2:
            stopBits = QSerialPort::TwoStop;        //3 位停止位
            break;
        default:
            qWarning() << "[getSerialConfig] 停止位索引无效：" << stopBitIndex;
            stopBits = QSerialPort::OneStop;  // 默认1位停止位
            break;
    }

    qInfo() << "getSerialConfig 串口号：" << portName << "波特率：" << baudRate << "数据位" << dataBits
                << "校验方式：" << parity << "停止位：" << stopBits;
    return !portName.isEmpty() && baudRate > 0;
}

void MainWindow::handleDataReceived(const QString &portName, const QByteArray &data)
{
    qInfo() << "串口数据接收 端口号[" << portName << "] 数据[" << data << "]";
    QWidget *widget0 = ui->widget_0->widget(2);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("serialPorts");
    if (!secondTab) return;

    QList<QComboBox*> comboBoxes = secondTab->findChildren<QComboBox*>();
    QString objName;
    foreach (QComboBox* combo, comboBoxes) {
        if (combo->currentText() == portName) {
            objName = combo->objectName();
            QComboBox *isOpenSerial = secondTab->findChild<QComboBox*>(objName + "_openSerialPort");
            if( isOpenSerial->currentIndex() ){
                qInfo() << "设备串口对应的标识：" << objName;
                break;
            }
        }
    }
    // 格式化接收时间
    QString timeStr = QDateTime::currentDateTime().toString("[yyyy-MM-dd hh:mm:ss] ");

    // 将数据显示到对应接收区域（修正了变量名和控件查找逻辑）
    QPlainTextEdit *reciveText = secondTab->findChild<QPlainTextEdit*>(objName + "_reciveData");
    if (reciveText) {
        QString dataStr = QString::fromUtf8(data);
        reciveText->setPlainText(timeStr + "@" + dataStr);
    } else {
        qWarning() << "未找到接收区域控件:" << portName + "_reciveData";
    }

    return;

}

void MainWindow::updateButtonState(const QString &portKey, const QString &statusInfo)
{
    QWidget *widget0 = ui->widget_0->widget(2);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("serialPorts");
    if (!secondTab) return;

    // 查找对应的串口状态控件
    QPushButton *serialStatus = secondTab->findChild<QPushButton*>(portKey + "_reciveStatus");
    if (serialStatus) {
        // 更新按钮状态
        serialStatus->setText(statusInfo);
    } else {
        qWarning() << "未找到串口状态控件:" << portKey + "_reciveStatus";
    }

    return;
}

void MainWindow::handlePortStatusChanged(const QString &portName, const QString &statusInfo)
{
    // 更新对应端口的按钮状态
    for (auto key : m_serialPorts.keys()) {
        if (m_serialPorts[key]->getPortName() == portName) {
            updateButtonState(key, statusInfo);
            break;
        }
    }
}

void MainWindow::sendToPort(const QString &portKey)
{
    if (!m_serialPorts.contains(portKey))
        return;

    QWidget *widget0 = ui->widget_0->widget(2);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("serialPorts");

    //串口未打开，不发数据
    QComboBox *serialOpen = secondTab->findChild<QComboBox*>(portKey + "_openSerialPort");
    if( 0 == serialOpen->currentIndex() ){
        updateButtonState(portKey, "串口未打开");
        return;
    }

    SerialPortManager *port = m_serialPorts[portKey];
    if (!port->isSerialPortOpen() && portKey != "RS485_2"){
        qInfo() << "[" << portKey << "] 打开失败！";
        return;
    }

    // 根据端口key获取对应发送区域的文本（修正了变量名portName为portKey）
    QByteArray data;
    // 将数据显示到对应接收区域（修正了变量名portName为portKey）
    QPlainTextEdit *sendText = secondTab->findChild<QPlainTextEdit*>(portKey + "_sendData");
    if (sendText) {
        //data = sendText->toPlainText().toUtf8();
        data = sendText->toPlainText().toLatin1();

        //添加回车选项
        data += "\n";

        if (!data.isEmpty()) {
            port->sendData(data);
        }
    } else {
        qWarning() << "未找到发送区域控件:" << portKey + "_sendData";
    }

    return;
}

void MainWindow::on_RS485_2_openSerialPort_activated(int index)
{
    qInfo() << "RS485_2 串口状态：" << index;
    SerialPortManager *port = m_serialPorts["RS485_2"];

    QString portName;
    qint32 baudRate;
    QSerialPort::DataBits dataBits;
    QSerialPort::Parity parity;
    QSerialPort::StopBits stopBits;
    if (getSerialConfig(0, "RS485_2", portName, baudRate, dataBits, parity, stopBits)) {
        port->initSerialPort(portName, baudRate, dataBits, parity, stopBits);
    }
}

void MainWindow::on_MCU_232_openSerialPort_activated(int index)
{
    qInfo() << "MCU_232 串口状态：" << index;
    SerialPortManager *port = m_serialPorts["MCU_232"];
    if (port->isSerialPortOpen()) {
        port->closeSerialPort();
    } else {
        QString portName;
        qint32 baudRate;
        QSerialPort::DataBits dataBits;
        QSerialPort::Parity parity;
        QSerialPort::StopBits stopBits;

        if (getSerialConfig(0, "MCU_232", portName, baudRate, dataBits, parity, stopBits)) {
            port->initSerialPort(portName, baudRate, dataBits, parity, stopBits);
        }
    }
}

void MainWindow::on_RS485_openSerialPort_activated(int index)
{
    qInfo() << "RS485 串口状态：" << index;
    SerialPortManager *port = m_serialPorts["RS485"];
    if (port->isSerialPortOpen()) {
        port->closeSerialPort();
    } else {
        QString portName;
        qint32 baudRate;
        QSerialPort::DataBits dataBits;
        QSerialPort::Parity parity;
        QSerialPort::StopBits stopBits;

        if (getSerialConfig(1, "RS485", portName, baudRate, dataBits, parity, stopBits)) {
            port->initSerialPort(portName, baudRate, dataBits, parity, stopBits);
        }
    }
}

void MainWindow::on_RS422_openSerialPort_activated(int index)
{
    qInfo() << "RS422 串口状态：" << index;
    SerialPortManager *port = m_serialPorts["RS422"];
    if (port->isSerialPortOpen()) {
        port->closeSerialPort();
    } else {
        QString portName;
        qint32 baudRate;
        QSerialPort::DataBits dataBits;
        QSerialPort::Parity parity;
        QSerialPort::StopBits stopBits;

        if (getSerialConfig(2, "RS422", portName, baudRate, dataBits, parity, stopBits)) {
            port->initSerialPort(portName, baudRate, dataBits, parity, stopBits);
        }
    }
}

void MainWindow::on_GPRMC_openSerialPort_activated(int index)
{
    qInfo() << "GPRMC 串口状态：" << index;
    SerialPortManager *port = m_serialPorts["GPRMC"];
    if (port->isSerialPortOpen()) {
        port->closeSerialPort();
    } else {
        QString portName;
        qint32 baudRate;
        QSerialPort::DataBits dataBits;
        QSerialPort::Parity parity;
        QSerialPort::StopBits stopBits;

        if (getSerialConfig(3, "GPRMC", portName, baudRate, dataBits, parity, stopBits)) {
            port->initSerialPort(portName, baudRate, dataBits, parity, stopBits);
        }
    }
}

// 单独的定时器处理函数，与按钮点击分离
void MainWindow::onSerialSendTimeout()
{
    // 定时发送数据
    for (auto key : m_serialPorts.keys()) {
        sendToPort(key);
    }
}

//发送所有数据
void MainWindow::on_serialPort_Send_clicked()
{
    QWidget *widget0 = ui->widget_0->widget(2);
    QPushButton* buttons = widget0->findChild<QPushButton*>("serialPort_Send");
    if (sendTimerSerial->isActive()) {
        // 停止定时器
        sendTimerSerial->stop();
        buttons->setText("发送");
        m_isSending = false;
        qInfo() << "串口通信定时器已停止";
    } else {
        // 启动定时器 - 先发送一次，再开始定时发送
        for (auto key : m_serialPorts.keys()) {
            sendToPort(key);
        }
        sendTimerSerial->start(1000); // 明确指定间隔时间
        buttons->setText("停止");
        m_isSending = true;
        qInfo() << "串口通信定时器已启动，间隔1000ms";
    }

    return;
}


void MainWindow::on_serialPort_Clear_clicked()
{
    qInfo() << "清除所有发送、接收数据...";
    QWidget *widget0 = ui->widget_0->widget(2);
    QTabWidget* secondTab = widget0->findChild<QTabWidget*>("serialPorts");
    if( !secondTab )
        qInfo() << "未找到QTabWidget控件";

    QList<QPlainTextEdit*> allTextEdits = secondTab->findChildren<QPlainTextEdit*>();
    // 遍历并清空每个文本控件
    foreach (QPlainTextEdit* edit, allTextEdits) {
        edit->clear();
    }

    QList<QPushButton*> buttons = secondTab->findChildren<QPushButton*>();
    foreach (QPushButton* btn, buttons) {
      btn->setStyleSheet(""); // 清除自定义样式
      btn->setEnabled(true); // 假设默认是启用状态，按需修改
      btn->setText("接收状态");
    }

    QList<QComboBox*> comboBoxes = secondTab->findChildren<QComboBox*>();
    foreach (QComboBox* combo, comboBoxes) {
        combo->setStyleSheet(""); // 清除自定义样式
        combo->setCurrentIndex(0); // 还原到第一个选项（默认初始状态）
        combo->setEnabled(true); // 恢复启用状态（按需调整）

        // 获取控件对象名进行判断
        const QString comboName = combo->objectName();
        const int suffixIndex = comboName.indexOf("_openSerialPort");

        if (suffixIndex != -1) {
            const QString prefix = comboName.left(suffixIndex);

            if (!m_serialPorts.contains(prefix)) {
                qWarning() << "未找到前缀为" << prefix << "的串口管理器";
                continue;
            }

            // 处理串口关闭逻辑
            SerialPortManager *port = m_serialPorts[prefix];
            if (port && port->isSerialPortOpen()) {
                qInfo() << "关闭串口：" << prefix;
                port->closeSerialPort();
            } else if (!port) {
                qWarning() << "串口管理器指针为空，前缀：" << prefix;
            }
        }
    }
}



// 接收服务端返回的数据
void MainWindow::onReadyReadUdp()
{
    qInfo() << "onReadyReadUdp...";
    if (!m_udpSocket) {
        qWarning() << "onReadyReadUdp: m_udpSocket 已释放";
        return;
    }

    while (m_udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        QHostAddress sender;
        quint16 senderPort;

        // 准备接收数据
        datagram.resize(m_udpSocket->pendingDatagramSize());
        qint64 bytesRead = m_udpSocket->readDatagram(datagram.data(), datagram.size(),
                                                    &sender, &senderPort);

        if (bytesRead != -1) {
            // 检查是否是我们发送的服务器返回的数据
            bool isFromServer = (sender == m_serverAddress && senderPort == m_serverPort);

            qInfo() << "UDP接收到数据：" << QString("%1 %2:%3 发送了 %4 字节: %5")
                      .arg(isFromServer ? "服务端" : "未知节点")
                      .arg(sender.toString())
                      .arg(senderPort)
                      .arg(bytesRead)
                      .arg(QString(datagram));

            // 记录到CSV文件
            cameraLogger->logCameraDatagram(datagram, sender, senderPort, isFromServer);

        }
    }
}

// 实现UDP发送方法
bool MainWindow::sendUdpMessage()
{
    if (m_udpSocket) {
       // 1. 先断开所有信号连接（避免信号触发已释放的对象）
       m_udpSocket->disconnect();
       // 2. 延迟删除（避免在信号处理中直接释放导致崩溃）
       m_udpSocket->deleteLater();
       m_udpSocket = nullptr;
   }

    // 创建UDP套接字
    m_udpSocket = new QUdpSocket(this);

    // 绑定到任意端口，用于接收数据
    if (!m_udpSocket->bind(QHostAddress(QHostAddress::Any), 0)) {
        qInfo() << "无法绑定到端口: " + m_udpSocket->errorString();
        return false;
    }
    qInfo() << "已绑定到地址: " << m_udpSocket->localAddress().toString()
                << " 端口: " << m_udpSocket->localPort();

    // 日志路径处理
    QString defaultPath = QString(PROJECT_DIR) + "/log";
    QDir logDir(defaultPath);
    if (!logDir.exists()) {
        logDir.mkpath("."); // 创建日志目录
    }

    QString csvFile = defaultPath + "/BrainBox_J300P_Camera";
    // 确保日志文件已初始化
    if ( !cameraLogger->initLogFile(csvFile, "CSV") ) {
        qInfo() << "无法初始化日志文件，无法记录数据";
        return false;
    }

    qInfo() << "已绑定到端口: " + QString::number(m_udpSocket->localPort());
    bool connectSuccess = connect(m_udpSocket, &QUdpSocket::readyRead, this, &MainWindow::onReadyReadUdp);
    if (!connectSuccess) {
        qInfo() << "信号槽连接失败";
        m_udpSocket->deleteLater();
        m_udpSocket = nullptr;
        return false;
    }

    // 保存服务器信息
    QString address = "192.168.10.15";
    m_serverAddress.setAddress(address);
    m_serverPort = 1998;

    // 发送数据
    QString message = "hi";
    QByteArray data = message.toUtf8();
    qint64 bytesSent = m_udpSocket->writeDatagram(data, m_serverAddress, m_serverPort);

    if (bytesSent == -1) {
        qInfo() << "发送失败: " + m_udpSocket->errorString();
        m_udpSocket->deleteLater();
        m_udpSocket = nullptr;
        return false;
    }

    qInfo() << "已发送 " << bytesSent << " 字节到 "
                << m_serverAddress.toString() << ":" << m_serverPort;

    return true;
}


// 视频播放初始化
void MainWindow::initVideoPlayer()
{
    QWidget *widget0 = ui->widget_0->widget(3);
    startBt = widget0->findChild<QPushButton*>("camera_start");
    videoLabel = widget0->findChild<QLabel*>("camera_play");

    // 初始化视频流对象
    if (!video_stream_) {
        video_stream_ = new VideoStream(this);
        setupVideoConnections();
    }

    // 初始化相机日志器
    if (!cameraLogger) {
        cameraLogger = new CanAscLogger(this);
    }
}

// 设置视频流信号槽连接
void MainWindow::setupVideoConnections()
{
    if (!video_stream_) return;

    // 断开已有连接，避免重复连接
    disconnect(video_stream_, nullptr, this, nullptr);

    // 连接视频帧就绪信号
    connect(video_stream_, &VideoStream::frameReady,
            this, &MainWindow::updateFrame, Qt::QueuedConnection);

    // 连接帧率更新信号
    connect(video_stream_, &VideoStream::frameRateUpdated,
            this, &MainWindow::onFrameRateUpdated);

    // 连接视频初始化状态信号
    connect(video_stream_, &VideoStream::sendVideoinitialized,
            this, &MainWindow::onVideoInitialized);

    // 连接服务器连接失败信号
    connect(video_stream_, &VideoStream::connectserverfailed,
            this, &MainWindow::onVideoConnectionFailed);
}

// 处理视频初始化结果 - 适配单按钮
void MainWindow::onVideoInitialized(bool isReady)
{
    is_playing_ = isReady;
    if (is_playing_) {
        startBt->setText("停止播放");
        //videoLabel->setText(""); // 清除初始文本
        showStatusMessage("视频播放中...");
        qInfo() << "车载相机视频流初始化成功";
    } else {
        startBt->setText("开始播放");
        showStatusMessage("视频初始化失败");
        //videoLabel->setText("视频初始化失败");
    }
}

// 处理视频连接失败 - 简化提示
void MainWindow::onVideoConnectionFailed()
{
    is_playing_ = false;
    startBt->setText("开始播放");
    //videoLabel->setText("无法连接到相机");
    showStatusMessage("无法连接到相机服务器，5秒后重试...");

    // 尝试重新连接
    QTimer::singleShot(5000, this, &MainWindow::on_camera_start_clicked);
}

// 更新帧率显示 - 在QLabel上显示
void MainWindow::onFrameRateUpdated(double fps)
{
    // 在视频标签上方显示帧率信息
    int roundedFps = qRound(fps);
    QString statusText = QString("帧率: %1 FPS").arg(roundedFps);
    showStatusMessage(statusText);
}

// 简化的状态消息显示
void MainWindow::showStatusMessage(const QString &message)
{
    qInfo() << "showStatusMessage: " << message;
    QWidget *widget0 = ui->widget_0->widget(3);
    QLabel* statusLabel = widget0->findChild<QLabel*>("camera_status");
    statusLabel->setText(message);
    // 3秒后清除临时消息
//    QTimer::singleShot(3000, [this]() {
//        if (is_playing_ && !videoLabel->text().contains("帧率")) {
//            videoLabel->clear();
//        }
//    });

    return;
}

// 停止视频流
void MainWindow::stopVideoStream()
{
    if (video_stream_) {
        video_stream_->close();
        video_stream_->wait(1000);
    }

    // 停止UDP通信
    if (m_udpSocket) {
        m_udpSocket->disconnect();
        m_udpSocket->deleteLater();
        m_udpSocket = nullptr;
    }

    // 关闭日志文件
    if (cameraLogger) {
        cameraLogger->closeLogFile();
    }

    is_playing_ = false;
    startBt->setText("开始播放");
    //videoLabel->clear();
    showStatusMessage("视频已停止");
}

// 更新视频帧显示
void MainWindow::updateFrame(const QImage &frame)
{
    if ( video_stream_->is8In1Frame(frame) ) {
        QWidget *widget8 = ui->widget_0->widget(3);
        qInfo() << "处理帧8合1图片格式...";
        int subWidth = frame.width() / 4;
        int subHeight = frame.height() / 2;

        QList<QImage> subFrames;

        for (int row = 0; row < 2; ++row) {
            for (int col = 0; col < 4; ++col) {
                // 从大帧中裁剪出小画面
                QRect subRect(col * subWidth, row * subHeight, subWidth, subHeight);
                QImage subFrame = frame.copy(subRect);
                subFrames.append(subFrame);
            }
        }
        // ========== 渲染到界面==========
       for (int i = 0; i < 8 && i < subFrames.size(); ++i) {
           QLabel* subLabel = widget8->findChild<QLabel*>(QString("camera_play_%1").arg(i));
           if (subLabel) {
               QImage scaledSub = subFrames[i].scaled(
                   subLabel->size(),
                   Qt::KeepAspectRatio,
                   Qt::FastTransformation
               );
               subLabel->setPixmap(QPixmap::fromImage(scaledSub));
           }
       }

        return;
    }

    if( !videoLabel )
        return;

    if (frame.isNull() || frame.width() <= 0 || frame.height() <= 0) {
      qWarning() << "[updateFrame] 接收空帧或无效分辨率帧";
      videoLabel->clear(); // 清空标签
      videoLabel->setText("无视频信号..."); // 显示提示文字
      showStatusMessage("无视频信号");
      return;
    }

    QSize labelSize = videoLabel->size();
    QImage scaledFrame = frame.scaled(
        labelSize,
        Qt::KeepAspectRatio,  // 保持宽高比
        Qt::FastTransformation // 快速缩放，优先性能 //Qt::SmoothTransformation // 平滑缩放（兼顾清晰度，性能允许时使用）
    );

    QPixmap videoPixmap = QPixmap::fromImage(scaledFrame);

    videoLabel->clear();
    videoLabel->setPixmap(videoPixmap);

    videoLabel->setAlignment(Qt::AlignCenter); // 帧居中显示
}

// 视频播放/停止按钮点击事件
void MainWindow::on_camera_start_clicked()
{
    // 如果正在播放，则停止
    if (is_playing_) {
        stopVideoStream();
        return;
    }

    // 初始化视频播放器
    initVideoPlayer();

    // 停止可能存在的旧连接
    if (video_stream_->isRunning()) {
        video_stream_->close();
    }

    // UDP发送及接收并记录数据
    if (!sendUdpMessage()) {
        showStatusMessage("UDP初始化失败，无法启动视频");
        return;
    }

    // 获取RTSP地址（根据实际情况修改
    QString rtspAddr = "rtsp://192.168.10.15:8554/v4l2";

    // 打开视频流
    if (!video_stream_->open(rtspAddr)) {
        qDebug() << "无法初始化视频流: " << rtspAddr;
        showStatusMessage("视频流初始化失败");
    }
    else {
        showStatusMessage("正在连接到相机...");
    }
}
